package com.zhang.authority.service.impl;

import com.zhang.authority.model.config.Role;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 内容摘抄自InMemoryRegisteredClientRepository
 *
 * @author zhangFanJun
 * @date 2024-07-09 17:22
 **/
@Slf4j
@Service
public class InMemoryClientRepository implements RegisteredClientRepository, InitializingBean {

    @Resource
    private PasswordEncoder passwordEncoder;
    private final Map<String, RegisteredClient> idRegistrationMap = new ConcurrentHashMap<>();
    private final Map<String, RegisteredClient> clientIdRegistrationMap = new ConcurrentHashMap<>();

    @Override
    public void afterPropertiesSet() throws Exception {

        TokenSettings tokenSettings = TokenSettings.builder().accessTokenTimeToLive(Duration.ofDays(1)).refreshTokenTimeToLive(Duration.ofDays(7)).build();
        RegisteredClient registration = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("server")
                .clientSecret(passwordEncoder.encode("server"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .tokenSettings(tokenSettings)
                .redirectUri("http://localhost:8080/login/oauth2/code/custom")
//                .scope(OidcScopes.OPENID)
                .scope(Role.USER.getRoleName())
//                .scope("api.read")
                .build();

        Assert.notNull(registration, "registration cannot be null");
        assertUniqueIdentifiers(registration, idRegistrationMap);
        idRegistrationMap.put(registration.getId(), registration);
        clientIdRegistrationMap.put(registration.getClientId(), registration);
        log.info("完成了客户端的初始化:{}",registration);
    }

    private void assertUniqueIdentifiers(RegisteredClient registeredClient, Map<String, RegisteredClient> registrations) {

        registrations.values().forEach(registration -> {
            if (registeredClient.getId().equals(registration.getId())) {
                throw new IllegalArgumentException("Registered client must be unique. " +
                        "Found duplicate identifier: " + registeredClient.getId());
            }
            if (registeredClient.getClientId().equals(registration.getClientId())) {
                throw new IllegalArgumentException("Registered client must be unique. " +
                        "Found duplicate client identifier: " + registeredClient.getClientId());
            }
            if (StringUtils.hasText(registeredClient.getClientSecret()) &&
                    registeredClient.getClientSecret().equals(registration.getClientSecret())) {
                throw new IllegalArgumentException("Registered client must be unique. " +
                        "Found duplicate client secret for identifier: " + registeredClient.getId());
            }
        });
    }


    @Override
    public void save(RegisteredClient registeredClient) {
        Assert.notNull(registeredClient, "registeredClient cannot be null");
        assertUniqueIdentifiers(registeredClient, this.idRegistrationMap);
        this.idRegistrationMap.put(registeredClient.getId(), registeredClient);
        this.clientIdRegistrationMap.put(registeredClient.getClientId(), registeredClient);
    }

    @Nullable
    @Override
    public RegisteredClient findById(String id) {

        log.info("通过id获取客户信息：{}",id);
        Assert.hasText(id, "id cannot be empty");
        return this.idRegistrationMap.get(id);
    }

    @Nullable
    @Override
    public RegisteredClient findByClientId(String clientId) {

        log.info("通过客户id获取客户信息:{}",clientId);
        Assert.hasText(clientId, "clientId cannot be empty");
        return this.clientIdRegistrationMap.get(clientId);
    }

}
